/*!

 Holder - 2.3.2 - client side image placeholders
 (c) 2012-2014 Ivan Malopinsky / http://imsky.co

 Provided under the MIT License.
 Commercial use requires attribution.

 */
var Holder = Holder || {};
(function (app, win) {
    var system_config = {
        use_svg: false,
        use_canvas: false,
        use_fallback: false
    };
    var instance_config = {};
    var preempted = false;
    canvas = document.createElement('canvas');
    var dpr = 1, bsr = 1;
    var resizable_images = [];

    if (!canvas.getContext) {
        system_config.use_fallback = true;
    } else {
        if (canvas.toDataURL("image/png")
                .indexOf("data:image/png") < 0) {
            //Android doesn't support data URI
            system_config.use_fallback = true;
        } else {
            var ctx = canvas.getContext("2d");
        }
    }

    if (!!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect) {
        system_config.use_svg = true;
        system_config.use_canvas = false;
    }

    if (!system_config.use_fallback) {
        dpr = window.devicePixelRatio || 1,
            bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
    }

    var ratio = dpr / bsr;

    var settings = {
        domain: "holder.js",
        images: "img",
        bgnodes: ".holderjs",
        themes: {
            "gray": {
                background: "#eee",
                foreground: "#aaa",
                size: 12
            },
            "social": {
                background: "#3a5a97",
                foreground: "#fff",
                size: 12
            },
            "industrial": {
                background: "#434A52",
                foreground: "#C2F200",
                size: 12
            },
            "sky": {
                background: "#0D8FDB",
                foreground: "#fff",
                size: 12
            },
            "vine": {
                background: "#39DBAC",
                foreground: "#1E292C",
                size: 12
            },
            "lava": {
                background: "#F8591A",
                foreground: "#1C2846",
                size: 12
            }
        },
        stylesheet: ""
    };
    app.flags = {
        dimensions: {
            regex: /^(\d+)x(\d+)$/,
            output: function (val) {
                var exec = this.regex.exec(val);
                return {
                    width: +exec[1],
                    height: +exec[2]
                }
            }
        },
        fluid: {
            regex: /^([0-9%]+)x([0-9%]+)$/,
            output: function (val) {
                var exec = this.regex.exec(val);
                return {
                    width: exec[1],
                    height: exec[2]
                }
            }
        },
        colors: {
            regex: /#([0-9a-f]{3,})\:#([0-9a-f]{3,})/i,
            output: function (val) {
                var exec = this.regex.exec(val);
                return {
                    size: settings.themes.gray.size,
                    foreground: "#" + exec[2],
                    background: "#" + exec[1]
                }
            }
        },
        text: {
            regex: /text\:(.*)/,
            output: function (val) {
                return this.regex.exec(val)[1];
            }
        },
        font: {
            regex: /font\:(.*)/,
            output: function (val) {
                return this.regex.exec(val)[1];
            }
        },
        auto: {
            regex: /^auto$/
        },
        textmode: {
            regex: /textmode\:(.*)/,
            output: function (val) {
                return this.regex.exec(val)[1];
            }
        }
    }

    function text_size(width, height, template) {
        height = parseInt(height, 10);
        width = parseInt(width, 10);
        var bigSide = Math.max(height, width)
        var smallSide = Math.min(height, width)
        var scale = 1 / 12;
        var newHeight = Math.min(smallSide * 0.75, 0.75 * bigSide * scale);
        return {
            height: Math.round(Math.max(template.size, newHeight))
        }
    }

    var svg_el = (function () {
        //Prevent IE <9 from initializing SVG renderer
        if (!window.XMLSerializer) return;
        var serializer = new XMLSerializer();
        var svg_ns = "http://www.w3.org/2000/svg"
        var svg = document.createElementNS(svg_ns, "svg");
        //IE throws an exception if this is set and Chrome requires it to be set
        if (svg.webkitMatchesSelector) {
            svg.setAttribute("xmlns", "http://www.w3.org/2000/svg")
        }
        var bg_el = document.createElementNS(svg_ns, "rect")
        var text_el = document.createElementNS(svg_ns, "text")
        var textnode_el = document.createTextNode(null)
        text_el.setAttribute("text-anchor", "middle")
        text_el.appendChild(textnode_el)
        svg.appendChild(bg_el)
        svg.appendChild(text_el)

        return function (props) {
            svg.setAttribute("width", props.width);
            svg.setAttribute("height", props.height);
            bg_el.setAttribute("width", props.width);
            bg_el.setAttribute("height", props.height);
            bg_el.setAttribute("fill", props.template.background);
            text_el.setAttribute("x", props.width / 2)
            text_el.setAttribute("y", props.height / 2)
            textnode_el.nodeValue = props.text
            text_el.setAttribute("style", css_properties({
                "fill": props.template.foreground,
                "font-weight": "bold",
                "font-size": props.text_height + "px",
                "font-family": props.font,
                "dominant-baseline": "central"
            }))
            return serializer.serializeToString(svg)
        }
    })()

    function css_properties(props) {
        var ret = [];
        for (p in props) {
            if (props.hasOwnProperty(p)) {
                ret.push(p + ":" + props[p])
            }
        }
        return ret.join(";")
    }

    function draw_canvas(args) {
        var ctx = args.ctx,
            dimensions = args.dimensions,
            template = args.template,
            ratio = args.ratio,
            holder = args.holder,
            literal = holder.textmode == "literal",
            exact = holder.textmode == "exact";

        var ts = text_size(dimensions.width, dimensions.height, template);
        var text_height = ts.height;
        var width = dimensions.width * ratio,
            height = dimensions.height * ratio;
        var font = template.font ? template.font : "Arial,Helvetica,sans-serif";
        canvas.width = width;
        canvas.height = height;
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillStyle = template.background;
        ctx.fillRect(0, 0, width, height);
        ctx.fillStyle = template.foreground;
        ctx.font = "bold " + text_height + "px " + font;
        var text = template.text ? template.text : (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));
        if (literal) {
            var dimensions = holder.dimensions;
            text = dimensions.width + "x" + dimensions.height;
        }
        else if (exact && holder.exact_dimensions) {
            var dimensions = holder.exact_dimensions;
            text = (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));
        }
        var text_width = ctx.measureText(text).width;
        if (text_width / width >= 0.75) {
            text_height = Math.floor(text_height * 0.75 * (width / text_width));
        }
        //Resetting font size if necessary
        ctx.font = "bold " + (text_height * ratio) + "px " + font;
        ctx.fillText(text, (width / 2), (height / 2), width);
        return canvas.toDataURL("image/png");
    }

    function draw_svg(args) {
        var dimensions = args.dimensions,
            template = args.template,
            holder = args.holder,
            literal = holder.textmode == "literal",
            exact = holder.textmode == "exact";

        var ts = text_size(dimensions.width, dimensions.height, template);
        var text_height = ts.height;
        var width = dimensions.width,
            height = dimensions.height;

        var font = template.font ? template.font : "Arial,Helvetica,sans-serif";
        var text = template.text ? template.text : (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));

        if (literal) {
            var dimensions = holder.dimensions;
            text = dimensions.width + "x" + dimensions.height;
        }
        else if (exact && holder.exact_dimensions) {
            var dimensions = holder.exact_dimensions;
            text = (Math.floor(dimensions.width) + "x" + Math.floor(dimensions.height));
        }
        var string = svg_el({
            text: text,
            width: width,
            height: height,
            text_height: text_height,
            font: font,
            template: template
        })
        return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(string)));
    }

    function draw(args) {
        if (instance_config.use_canvas && !instance_config.use_svg) {
            return draw_canvas(args);
        }
        else {
            return draw_svg(args);
        }
    }

    function render(mode, el, holder, src) {
        var dimensions = holder.dimensions,
            theme = holder.theme,
            text = holder.text ? decodeURIComponent(holder.text) : holder.text;
        var dimensions_caption = dimensions.width + "x" + dimensions.height;
        theme = (text ? extend(theme, {
            text: text
        }) : theme);
        theme = (holder.font ? extend(theme, {
            font: holder.font
        }) : theme);
        el.setAttribute("data-src", src);
        holder.theme = theme;
        el.holder_data = holder;

        if (mode == "image") {
            el.setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption);
            if (instance_config.use_fallback || !holder.auto) {
                el.style.width = dimensions.width + "px";
                el.style.height = dimensions.height + "px";
            }
            if (instance_config.use_fallback) {
                el.style.backgroundColor = theme.background;
            } else {
                el.setAttribute("src", draw({
                    ctx: ctx,
                    dimensions: dimensions,
                    template: theme,
                    ratio: ratio,
                    holder: holder
                }));

                if (holder.textmode && holder.textmode == "exact") {
                    resizable_images.push(el);
                    resizable_update(el);
                }

            }
        } else if (mode == "background") {
            if (!instance_config.use_fallback) {
                el.style.backgroundImage = "url(" + draw({
                        ctx: ctx,
                        dimensions: dimensions,
                        template: theme,
                        ratio: ratio,
                        holder: holder
                    }) + ")";
                el.style.backgroundSize = dimensions.width + "px " + dimensions.height + "px";
            }
        } else if (mode == "fluid") {
            el.setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption);
            if (dimensions.height.slice(-1) == "%") {
                el.style.height = dimensions.height
            } else if (holder.auto == null || !holder.auto) {
                el.style.height = dimensions.height + "px"
            }
            if (dimensions.width.slice(-1) == "%") {
                el.style.width = dimensions.width
            } else if (holder.auto == null || !holder.auto) {
                el.style.width = dimensions.width + "px"
            }
            if (el.style.display == "inline" || el.style.display === "" || el.style.display == "none") {
                el.style.display = "block";
            }

            set_initial_dimensions(el)

            if (instance_config.use_fallback) {
                el.style.backgroundColor = theme.background;
            } else {
                resizable_images.push(el);
                resizable_update(el);
            }
        }
    }

    function dimension_check(el, callback) {
        var dimensions = {
            height: el.clientHeight,
            width: el.clientWidth
        };
        if (!dimensions.height && !dimensions.width) {
            el.setAttribute("data-holder-invisible", true)
            callback.call(this, el)
        }
        else {
            el.removeAttribute("data-holder-invisible")
            return dimensions;
        }
    }

    function set_initial_dimensions(el) {
        if (el.holder_data) {
            var dimensions = dimension_check(el, app.invisible_error_fn(set_initial_dimensions))
            if (dimensions) {
                var holder = el.holder_data;
                holder.initial_dimensions = dimensions;
                holder.fluid_data = {
                    fluid_height: holder.dimensions.height.slice(-1) == "%",
                    fluid_width: holder.dimensions.width.slice(-1) == "%",
                    mode: null
                }
                if (holder.fluid_data.fluid_width && !holder.fluid_data.fluid_height) {
                    holder.fluid_data.mode = "width"
                    holder.fluid_data.ratio = holder.initial_dimensions.width / parseFloat(holder.dimensions.height)
                }
                else if (!holder.fluid_data.fluid_width && holder.fluid_data.fluid_height) {
                    holder.fluid_data.mode = "height";
                    holder.fluid_data.ratio = parseFloat(holder.dimensions.width) / holder.initial_dimensions.height
                }
            }
        }
    }

    function resizable_update(element) {
        var images;
        if (element.nodeType == null) {
            images = resizable_images;
        } else {
            images = [element]
        }
        for (var i in images) {
            if (!images.hasOwnProperty(i)) {
                continue;
            }
            var el = images[i]
            if (el.holder_data) {
                var holder = el.holder_data;
                var dimensions = dimension_check(el, app.invisible_error_fn(resizable_update))
                if (dimensions) {
                    if (holder.fluid) {
                        if (holder.auto) {
                            switch (holder.fluid_data.mode) {
                                case "width":
                                    dimensions.height = dimensions.width / holder.fluid_data.ratio;
                                    break;
                                case "height":
                                    dimensions.width = dimensions.height * holder.fluid_data.ratio;
                                    break;
                            }
                        }
                        el.setAttribute("src", draw({
                            ctx: ctx,
                            dimensions: dimensions,
                            template: holder.theme,
                            ratio: ratio,
                            holder: holder
                        }))
                    }
                    if (holder.textmode && holder.textmode == "exact") {
                        holder.exact_dimensions = dimensions;
                        el.setAttribute("src", draw({
                            ctx: ctx,
                            dimensions: holder.dimensions,
                            template: holder.theme,
                            ratio: ratio,
                            holder: holder
                        }))
                    }
                }
            }
        }
    }

    function parse_flags(flags, options) {
        var ret = {
            theme: extend(settings.themes.gray, {})
        };
        var render = false;
        for (var fl = flags.length, j = 0; j < fl; j++) {
            var flag = flags[j];
            if (app.flags.dimensions.match(flag)) {
                render = true;
                ret.dimensions = app.flags.dimensions.output(flag);
            } else if (app.flags.fluid.match(flag)) {
                render = true;
                ret.dimensions = app.flags.fluid.output(flag);
                ret.fluid = true;
            } else if (app.flags.textmode.match(flag)) {
                ret.textmode = app.flags.textmode.output(flag)
            } else if (app.flags.colors.match(flag)) {
                ret.theme = app.flags.colors.output(flag);
            } else if (options.themes[flag]) {
                //If a theme is specified, it will override custom colors
                if (options.themes.hasOwnProperty(flag)) {
                    ret.theme = extend(options.themes[flag], {});
                }
            } else if (app.flags.font.match(flag)) {
                ret.font = app.flags.font.output(flag);
            } else if (app.flags.auto.match(flag)) {
                ret.auto = true;
            } else if (app.flags.text.match(flag)) {
                ret.text = app.flags.text.output(flag);
            }
        }
        return render ? ret : false;
    }

    for (var flag in app.flags) {
        if (!app.flags.hasOwnProperty(flag)) continue;
        app.flags[flag].match = function (val) {
            return val.match(this.regex)
        }
    }

    app.invisible_error_fn = function (fn) {
        return function (el) {
            if (el.hasAttribute("data-holder-invisible")) {
                throw new Error("Holder: invisible placeholder")
            }
        }
    }

    app.add_theme = function (name, theme) {
        name != null && theme != null && (settings.themes[name] = theme);
        return app;
    };

    app.add_image = function (src, el) {
        var node = selector(el);
        if (node.length) {
            for (var i = 0, l = node.length; i < l; i++) {
                var img = document.createElement("img")
                img.setAttribute("data-src", src);
                node[i].appendChild(img);
            }
        }
        return app;
    };

    app.run = function (o) {

        instance_config = extend({}, system_config)
        preempted = true;

        var options = extend(settings, o),
            images = [],
            imageNodes = [],
            bgnodes = [];

        if (options.use_canvas != null && options.use_canvas) {
            instance_config.use_canvas = true;
            instance_config.use_svg = false;
        }

        if (typeof (options.images) == "string") {
            imageNodes = selector(options.images);
        } else if (window.NodeList && options.images instanceof window.NodeList) {
            imageNodes = options.images;
        } else if (window.Node && options.images instanceof window.Node) {
            imageNodes = [options.images];
        } else if (window.HTMLCollection && options.images instanceof window.HTMLCollection) {
            imageNodes = options.images
        }

        if (typeof (options.bgnodes) == "string") {
            bgnodes = selector(options.bgnodes);
        } else if (window.NodeList && options.elements instanceof window.NodeList) {
            bgnodes = options.bgnodes;
        } else if (window.Node && options.bgnodes instanceof window.Node) {
            bgnodes = [options.bgnodes];
        }
        for (i = 0, l = imageNodes.length; i < l; i++) images.push(imageNodes[i]);

        var holdercss = document.getElementById("holderjs-style");
        if (!holdercss) {
            holdercss = document.createElement("style");
            holdercss.setAttribute("id", "holderjs-style");
            holdercss.type = "text/css";
            document.getElementsByTagName("head")[0].appendChild(holdercss);
        }

        if (!options.nocss) {
            if (holdercss.styleSheet) {
                holdercss.styleSheet.cssText += options.stylesheet;
            } else {
                if (options.stylesheet.length) {
                    holdercss.appendChild(document.createTextNode(options.stylesheet));
                }
            }
        }

        var cssregex = new RegExp(options.domain + "\/(.*?)\"?\\)");
        for (var l = bgnodes.length, i = 0; i < l; i++) {
            var src = window.getComputedStyle(bgnodes[i], null)
                .getPropertyValue("background-image");
            var flags = src.match(cssregex);
            var bgsrc = bgnodes[i].getAttribute("data-background-src");
            if (flags) {
                var holder = parse_flags(flags[1].split("/"), options);
                if (holder) {
                    render("background", bgnodes[i], holder, src);
                }
            } else if (bgsrc != null) {
                var holder = parse_flags(bgsrc.substr(bgsrc.lastIndexOf(options.domain) + options.domain.length + 1)
                    .split("/"), options);
                if (holder) {
                    render("background", bgnodes[i], holder, src);
                }
            }
        }
        for (l = images.length, i = 0; i < l; i++) {
            var attr_data_src, attr_src;
            attr_src = attr_data_src = src = null;
            try {
                attr_src = images[i].getAttribute("src");
                attr_datasrc = images[i].getAttribute("data-src");
            } catch (e) {
            }
            if (attr_datasrc == null && !!attr_src && attr_src.indexOf(options.domain) >= 0) {
                src = attr_src;
            } else if (!!attr_datasrc && attr_datasrc.indexOf(options.domain) >= 0) {
                src = attr_datasrc;
            }
            if (src) {
                var holder = parse_flags(src.substr(src.lastIndexOf(options.domain) + options.domain.length + 1).split("/"), options);
                if (holder) {
                    if (holder.fluid) {
                        render("fluid", images[i], holder, src)
                    } else {
                        render("image", images[i], holder, src);
                    }
                }
            }
        }
        return app;
    };

    contentLoaded(win, function () {
        if (window.addEventListener) {
            window.addEventListener("resize", resizable_update, false);
            window.addEventListener("orientationchange", resizable_update, false);
        } else {
            window.attachEvent("onresize", resizable_update)
        }
        preempted || app.run({});

        if (typeof window.Turbolinks === "object") {
            document.addEventListener("page:change", function () {
                app.run({})
            })
        }
    });
    if (typeof define === "function" && define.amd) {
        define([], function () {
            return app;
        });
    }

//github.com/davidchambers/Base64.js
    (function () {
        function t(t) {
            this.message = t
        }

        var e = "undefined" != typeof exports ? exports : this,
            r = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        t.prototype = Error(), t.prototype.name = "InvalidCharacterError", e.btoa || (e.btoa = function (e) {
            for (var o, n, a = 0, i = r, c = ""; e.charAt(0 | a) || (i = "=", a % 1); c += i.charAt(63 & o >> 8 - 8 * (a % 1))) {
                if (n = e.charCodeAt(a += .75), n > 255)throw new t("'btoa' failed");
                o = o << 8 | n
            }
            return c
        }), e.atob || (e.atob = function (e) {
            if (e = e.replace(/=+$/, ""), 1 == e.length % 4)throw new t("'atob' failed");
            for (var o, n, a = 0, i = 0, c = ""; n = e.charAt(i++); ~n && (o = a % 4 ? 64 * o + n : n, a++ % 4) ? c += String.fromCharCode(255 & o >> (6 & -2 * a)) : 0)n = r.indexOf(n);
            return c
        })
    })();

//getElementsByClassName polyfill
    document.getElementsByClassName || (document.getElementsByClassName = function (e) {
        var t = document, n, r, i, s = [];
        if (t.querySelectorAll)return t.querySelectorAll("." + e);
        if (t.evaluate) {
            r = ".//*[contains(concat(' ', @class, ' '), ' " + e + " ')]", n = t.evaluate(r, t, null, 0, null);
            while (i = n.iterateNext())s.push(i)
        } else {
            n = t.getElementsByTagName("*"), r = new RegExp("(^|\\s)" + e + "(\\s|$)");
            for (i = 0; i < n.length; i++)r.test(n[i].className) && s.push(n[i])
        }
        return s
    })

//getComputedStyle polyfill
    window.getComputedStyle || (window.getComputedStyle = function (e) {
        return this.el = e, this.getPropertyValue = function (t) {
            var n = /(\-([a-z]){1})/g;
            return t == "float" && (t = "styleFloat"), n.test(t) && (t = t.replace(n, function () {
                return arguments[2].toUpperCase()
            })), e.currentStyle[t] ? e.currentStyle[t] : null
        }, this
    })

//http://javascript.nwbox.com/ContentLoaded by Diego Perini with modifications
    function contentLoaded(n, t) {
        var l = "complete", s = "readystatechange", u = !1, h = u, c = !0, i = n.document, a = i.documentElement,
            e = i.addEventListener ? "addEventListener" : "attachEvent",
            v = i.addEventListener ? "removeEventListener" : "detachEvent", f = i.addEventListener ? "" : "on",
            r = function (e) {
                (e.type != s || i.readyState == l) && ((e.type == "load" ? n : i)[v](f + e.type, r, u), !h && (h = !0) && t.call(n, null))
            }, o = function () {
                try {
                    a.doScroll("left")
                } catch (n) {
                    setTimeout(o, 50);
                    return
                }
                r("poll")
            };
        if (i.readyState == l) t.call(n, "lazy"); else {
            if (i.createEventObject && a.doScroll) {
                try {
                    c = !n.frameElement
                } catch (y) {
                }
                c && o()
            }
            i[e](f + "DOMContentLoaded", r, u), i[e](f + s, r, u), n[e](f + "load", r, u)
        }
    }

//https://gist.github.com/991057 by Jed Schmidt with modifications
    function selector(a, b) {
        var a = a.match(/^(\W)?(.*)/), b = b || document,
            c = b["getElement" + (a[1] ? "#" == a[1] ? "ById" : "sByClassName" : "sByTagName")], d = c.call(b, a[2]),
            e = [];
        return null !== d && (e = d.length || 0 === d.length ? d : [d]), e
    }

//shallow object property extend
    function extend(a, b) {
        var c = {};
        for (var i in a) {
            if (a.hasOwnProperty(i)) {
                c[i] = a[i];
            }
        }
        for (var i in b) {
            if (b.hasOwnProperty(i)) {
                c[i] = b[i];
            }
        }
        return c
    }

//hasOwnProperty polyfill
    if (!Object.prototype.hasOwnProperty)
    /*jshint -W001, -W103 */
        Object.prototype.hasOwnProperty = function (prop) {
            var proto = this.__proto__ || this.constructor.prototype;
            return (prop in this) && (!(prop in proto) || proto[prop] !== this[prop]);
        }
    /*jshint +W001, +W103 */

})(Holder, window);
